home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Utilities / Type1Manager / src / t1objects.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-12  |  24.1 KB  |  901 lines

  1. /* $XConsortium: objects.c,v 1.11 94/03/23 14:28:05 gildea Exp $ */
  2. /* Copyright International Business Machines, Corp. 1991
  3.  * All Rights Reserved
  4.  * Copyright Lexmark International, Inc. 1991
  5.  * All Rights Reserved
  6.  *
  7.  * License to use, copy, modify, and distribute this software and its
  8.  * documentation for any purpose and without fee is hereby granted,
  9.  * provided that the above copyright notice appear in all copies and that
  10.  * both that copyright notice and this permission notice appear in
  11.  * supporting documentation, and that the name of IBM or Lexmark not be
  12.  * used in advertising or publicity pertaining to distribution of the
  13.  * software without specific, written prior permission.
  14.  *
  15.  * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
  16.  * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  18.  * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE
  19.  * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
  20.  * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF THE
  21.  * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
  22.  * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN NO EVENT SHALL
  23.  * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  24.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  25.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  26.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  27.  * THIS SOFTWARE.
  28.  */
  29.  
  30. /*
  31.  * OBJECTS Module - TYPE1IMAGER Objects Common Routines
  32.  *
  33.  * This module defines and implements the C structures that represent
  34.  * objects in the TYPE1IMAGER.  All common routines for manipulating these
  35.  * objects are defined in this module.  Specific routines for
  36.  * specific objects are defined in the modules that deal with that
  37.  * object type.
  38.  *
  39.  *
  40.  * &author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
  41.  */
  42.  
  43.  
  44. /************
  45. Include Files
  46.  
  47. The included files are:
  48. *************/
  49.  
  50. /*
  51.  * The following two includes are C standards; we include them because we
  52.  * use 'toupper' and the 'str'-type functions in this module.  Potentially
  53.  * these may be defined as macros; if these ".h" files do not exist on your
  54.  * system it is a pretty safe bet that these are external entry points and
  55.  * you do do not need to include these header files.
  56.  */
  57. #include  <ctype.h>
  58.  
  59. /* moved these includes from above the    */
  60. /*   was included first (it contains com- */
  61. /*   piler defines).  dsr 081291          */
  62.  
  63. #ifndef T1GST
  64. #include "global.h"
  65. #endif
  66.  
  67.  
  68. char MustCheckArgs = TRUE;
  69. char MustTraceCalls = FALSE;
  70. char MustCrash = TRUE;
  71. char InternalTrace = TRUE;
  72. char LineIOTrace = TRUE;
  73.  
  74. char ProcessHints = TRUE;
  75.  
  76. char SaveFontPaths = TRUE;
  77.  
  78. short CRASTERCompressionType = 1;
  79.  
  80. char ConicDebug = 0;
  81. char LineDebug = 0;
  82. char RegionDebug = 0;
  83. char PathDebug = 0;
  84. char FontDebug = 0;
  85. char SpaceDebug = 0;
  86. char StrokeDebug = 0;
  87. char MemoryDebug = 0;
  88. char HintDebug = 0;
  89. char ImageDebug = 0;
  90. char OffPageDebug = 0;
  91.  
  92. short CachedChars = 0x7FFF;
  93. short CachedFonts = 0x7FFF;
  94. int CacheBLimit = 12500;
  95. char Continuity = 2;
  96.  
  97.  
  98. //static char *TypeFmt(int type);
  99. //static void ObjectPostMortem(struct xobject *obj);
  100.  
  101.  
  102. /*
  103.  * Note that entry points that are intended for use external to TYPE1IMAGER
  104.  * begin with the characters xi.  Macros are used to make the names
  105.  * more mnemonic.
  106.  */
  107.  
  108. /*
  109.  * Note that entry points that intended for use within TYPE1IMAGER, but
  110.  * which must be global because they are used across module boundaries,
  111.  * begin with the characters I_.  Macros are used to make the names
  112.  * more mnemonic.
  113.  *
  114.  * Entry points totally within a module use mnemonic names and are
  115.  * declared static.  One of the compilers I used had a bug when
  116.  * static functions were passed as addresses.  Thus, some functions
  117.  * which are logically "static" are not so declared.
  118.  *
  119.  * Note also the trick of declaring routines, like Consume(), with a
  120.  * variable number of arguments.  To avoid the restrictions on variable
  121.  * numbers of arguments in the macro processor, we just replace the
  122.  * text 'Consume' with 'I_Consume'.
  123.  */
  124.  
  125.  
  126. /*
  127.  * RefRoll() Macro to Detect References Count Rollover
  128.  *
  129.  * The following macro is designed to check for reference count rollover.
  130.  * A return value of TRUE means rollover has not occurred; a return value
  131.  * of FALSE means we cannot increment the reference count.  Note also that
  132.  * those functions that use this macro must decrement the reference count
  133.  * afterwards.  3-26-91 PNM
  134.  */
  135. #define RefRoll(obj)  (++(obj)->references > 0)
  136.  
  137.  
  138. /*
  139.  * Allocate() - Allocating a Memory Block
  140.  *
  141.  * Allocate returns a pointer to memory object that is a copy of
  142.  * the template passed (if any).  In addition, extra bytes may be
  143.  * allocated contiguously with the object.  (This may be useful for
  144.  * variable size objects such as edge lists.  See :hdref refid=regions..)
  145.  *
  146.  * Allocate() always returns a non-immortal object, even if the template is
  147.  * immortal.  Therefore a non-NULL template must have a "flag" byte.
  148.  *
  149.  * If the template is NULL, then 'size' bytes are cleared to all NULLs.
  150.  *
  151.  * If the template is non-NULL, a new object is allocated in memory.
  152.  * It therefore seems logical that its reference count field should be
  153.  * set to 1. So, a nun-NULL template must also have a "references" field.
  154.  * PNM 3-26-91
  155.  */
  156. struct xobject *t1_Allocate(
  157.         int size,                /* number of bytes to allocate & initialize */
  158.         struct xobject *template, /* example structure to allocate */
  159.         int extra)                /* any extra uninitialized bytes needed contiguously */
  160. {
  161.     extern char *xiMalloc();
  162.  
  163.     struct xobject *r;
  164.  
  165.     /*
  166.      * round up 'size' and 'extra' to be an integer number of 'long's:
  167.      */
  168.     size = (size + sizeof(long) - 1) & -(int)sizeof(long);
  169.     extra = (extra + sizeof(long) - 1) & -(int)sizeof(long);
  170.  
  171.     if (size + extra <= 0)
  172.         t1_abort("Non-positive allocate?");
  173.     r = (struct xobject *)xiMalloc(size + extra);
  174.  
  175.     while (r == NULL)
  176.     {
  177.         if (!GimeSpace())
  178.         {
  179.             IfTrace1(TRUE, "malloc attempted %d bytes.\n",
  180.                  size + extra);
  181.             t1_abort("We have REALLY run out of memory");
  182.         }
  183.         r = (struct xobject *)xiMalloc(size + extra);
  184.     }
  185.  
  186.       /*
  187.        * copy the template into the new memory:
  188.        */
  189.     if (template != NULL)
  190.     {
  191.         /* Added references count decrement if template is not permanent.
  192.           This is for the case where Allocate is called by a Dupxxxx
  193.           function, which was in turn called by Unique(). (PNM)        */
  194.         if (!ISPERMANENT(template->flag))
  195.             --template->references;
  196.         LONGCOPY(r, template, size);
  197.         r->flag &= ~(ISPERMANENT(ON) | ISIMMORTAL(ON));
  198.         /* added reference field 3-2-6-91 PNM */
  199.         r->references = 1;
  200.     }
  201.     else
  202.     {
  203.         register char **p1;
  204.  
  205.         for (p1 = (char **)r; size > 0; size -= sizeof(char *))
  206.             *p1++ = NULL;
  207.     }
  208.  
  209. //    if (MemoryDebug > 1)
  210. //    {
  211. //        register long *L;
  212. //
  213. //        L = (long *)r;
  214. //        IfTrace4(TRUE, "Allocating at %x: %x %x %x\n",
  215. //             L, L[-1], L[0], L[1]);
  216. //    }
  217.  
  218.     return (r);
  219. }
  220.  
  221.  
  222. /*
  223.  * Free() - Frees an Allocated Object
  224.  *
  225.  * This routine makes a sanity check to make sure the "type" field of the
  226.  * standard object structure has not been cleared.  If the object is
  227.  * not a standard structure, then the macro "NonObjectFree" is available
  228.  * that does not perform this check.
  229.  *
  230.  * In either case, the object must not be the NULL pointer.  This preserves
  231.  * portability, as the C system xiFree() will not always accept NULL.
  232.  */
  233. void t1_Free(struct xobject *obj)
  234. {
  235.     if (obj->type == INVALIDTYPE)
  236.         t1_abort("Free of already freed object?");
  237.     obj->type = INVALIDTYPE;
  238.  
  239. //    if (MemoryDebug > 1)
  240. //    {
  241. //        register long *L;
  242. //
  243. //        L = (long *)obj;
  244. //        IfTrace4(TRUE, "Freeing at %x: %x %x %x\n", L, L[-1], L[0], L[1]);
  245. //    }
  246.  
  247.     xiFree(obj);
  248. }
  249.  
  250.  
  251. /*
  252.  * Permanent() - Makes an Object Permanent
  253.  *
  254.  * Real simple--just set a flag.  Every routine that consumes its objects
  255.  * (which is almost every user entry) must check this flag, and not consume
  256.  * the object if it is set.
  257.  *
  258.  * If a temporary object is made permanent, and there is more than one
  259.  * reference to it, we must first Copy() it, then set the ISPERMANENT
  260.  * flag. Note also that the reference count must be incremented when an
  261.  * object is changed from temporary to permanent (see the ISUNIQUE macro).
  262.  *
  263.  * Note that the purpose of this function is to convert an object into a
  264.  * permanent object:
  265.  *   If it was permanent to begin with, we do nothing;
  266.  *   If it was temporary and unique, we set the PERMANENT flag and increment
  267.  * the reference count;
  268.  *   If it was temporary and nonunique, we must make a unique Copy(), set
  269.  * the PERMANENT flag, and set the reference count to 2. We must also
  270.  * decrement the original object's reference count, because what we have
  271.  * done is to change one of the old temporary handles to a permanent one.
  272.  * 3-26-91 PNM
  273.  */
  274. struct xobject *t1_Permanent(struct xobject *obj)
  275. {
  276. //    IfTrace1((MustTraceCalls), "Permanent(%z)\n", obj);
  277.  
  278.     if ((obj != NULL) && (!(ISPERMANENT(obj->flag))))
  279.     {
  280.         /* there is a non-NULL, temporary object to be made permanent.
  281.          * If there are multiple references to this object, first get
  282.          * a new COPY().
  283.          * Note also that we have to decrement the reference count if
  284.          * we do a Copy() here, because we are consuming the temporary
  285.          * argument passed, and returning a unique, permanent one.
  286.          */
  287.         if (obj->references > 1)
  288.         {
  289.             obj = Copy(obj);
  290.         }
  291.         /* now set the permanent flag, and increment the reference
  292.          * count, since a temporary object has now become permanent. */
  293.         obj->references++;
  294.         obj->flag |= ISPERMANENT(ON);
  295.     }
  296.     return (obj);
  297. }
  298.  
  299.  
  300. /*
  301.  * Temporary() - Undoes the Effect of "Permanent()"
  302.  *
  303.  * This simply resets the "ISPERMANENT" flag.
  304.  *
  305.  * If a permanent object is made temporary, and there is more than one reference
  306.  * to it, we must first Copy() it, then reset the ISPERMANENT flag. However,
  307.  * if the permanent object has obly one reference, we need only decrement the
  308.  * reference count ( and reset the flag).
  309.  *
  310.  * Note that this function, in the case of a PERMANENT argument, basically
  311.  * converts the PERMANENT handle to a TEMPORARY one. Thus, in the case of
  312.  * a nonunique, permanent argument passed, we not only make a Copy(),
  313.  * we also decrement the reference count, to reflect the fact that we have
  314.  * lost a permanent handle and gained a temporary one.
  315.  * PNM 3-2-6-91
  316.  */
  317. struct xobject *t1_Temporary(struct xobject *obj)
  318. {
  319. //    IfTrace1((MustTraceCalls), "Temporary(%z)\n", obj);
  320.  
  321.     if (obj != NULL)
  322.     {
  323.         /* if it's already temporary, there's nothing to do. */
  324.         if ISPERMANENT(obj->flag)
  325.         {
  326.             /* if there are multiple references to this object, get a
  327.              * Copy we can safely alter. Recall that the reference count
  328.              * is incremented for permanent objects.
  329.              * Recall further that Copy returns an object with the
  330.              * same flag state and a reference count of 2 (for PERMANENT
  331.              * objects).
  332.              * Thus, regardless of whether or not we need to copy a
  333.              * permanent object, we still decrement its reference
  334.              * count and reset the flag.
  335.              */
  336.             if (obj->references != 2 || ISIMMORTAL(obj->flag))
  337.             {
  338.                 /* not unique; consume handle, get a temporary Copy! */
  339.                 obj = Copy(obj);
  340.             }
  341.             /* else decrement the reference count (since it's going from
  342.                   permanent to temporary) and clear the flag. */
  343.             else
  344.             {
  345.                 obj->references--;
  346.                 obj->flag &= ~ISPERMANENT(ON);
  347.             }
  348.         }
  349.     }
  350.     return (obj);
  351. }
  352.  
  353.  
  354. /*
  355.  * Dup() - Duplicate an Object
  356.  *
  357.  * Dup will increment the reference count of an object, only making a
  358.  * Copy() if needed.
  359.  * Note that Dup() retains the state of the permanent flag.
  360.  * 3-26-91 PNM
  361.  */
  362. struct xobject *t1_Dup(struct xobject *obj)
  363. {
  364.     char oldflag;        /* copy of original object's flag byte */
  365.  
  366. //    IfTrace1((MustTraceCalls), "Dup(%z)\n", obj);
  367.  
  368.     if (obj == NULL)
  369.         return (NULL);
  370.     /* An immortal object must be Copy'ed, so that we get a mortal
  371.           copy of it, since we try not to destroy immortal objects. */
  372.     if (ISIMMORTAL(obj->flag))
  373.         return (Copy(obj));
  374.  
  375.     /* if incrementing the reference count doesn't cause the count
  376.           to wrap, simply return the object with the count bumped. Note
  377.           that the RefRoll macro increments the count to perform the
  378.           rollover check, so we must decrement the count. */
  379.     if (RefRoll(obj))
  380.         return (obj);
  381.  
  382.     /* that didn't work out, so put the count back and call Copy(). */
  383.     --obj->references;
  384.     oldflag = obj->flag;
  385.     obj = Copy(obj);
  386.     if (ISPERMANENT(oldflag))
  387.         obj = Permanent(obj);
  388.     return (obj);
  389. }
  390.  
  391.  
  392. /*
  393.  * Copy() - Make a New Copy of an Object
  394.  *
  395.  * This is the generic Copy() where the object type is unknown.  There
  396.  * are specific Copyxxx functions for known object types.
  397.  *
  398.  * Copy will create a NEW temporary object, and WILL NOT simply bump the
  399.  * reference count.
  400.  *
  401.  * Sometimes duplicating an object is just as simple as Allocating with it
  402.  * as a template.  But other objects are complicated linked lists.  So, we
  403.  * let each module provide us a routine (or macro) that duplicates the
  404.  * objects it knows about.
  405.  */
  406. struct xobject *t1_Copy(struct xobject *obj)
  407. {
  408.     if (obj == NULL)
  409.         return (NULL);
  410.  
  411.     if (ISPATHTYPE(obj->type))
  412.         obj = (struct xobject *)CopyPath(obj);
  413.     else
  414.         switch (obj->type)
  415.         {
  416.         case SPACETYPE:
  417.             obj = (struct xobject *)CopySpace(obj);
  418.             break;
  419.         case FONTTYPE:
  420.             obj = (struct xobject *)CopyFont(obj);
  421.             break;
  422.         case REGIONTYPE:
  423.             obj = (struct xobject *)CopyRegion(obj);
  424.             break;
  425.         case PICTURETYPE:
  426.             obj = (struct xobject *)CopyPicture(obj);
  427.             break;
  428.         case LINESTYLETYPE:
  429.             obj = (struct xobject *)CopyLineStyle(obj);
  430.             break;
  431.         case STROKEPATHTYPE:
  432.             obj = (struct xobject *)CopyStrokePath(obj);
  433.             break;
  434.         case CLUTTYPE:
  435.             obj = (struct xobject *)CopyCLUT(obj);
  436.             break;
  437.         default:
  438.             return (ArgErr("Copy: invalid object", obj, NULL));
  439.         }
  440.  
  441.     return (obj);
  442. }
  443.  
  444.  
  445. /*
  446.  * Destroy() - Destroys an Object
  447.  *
  448.  * This can get complicated.  Just like with Copy(), we let the experts
  449.  * handle it.
  450.  */
  451. struct xobject *t1_Destroy(struct xobject *obj)
  452. {
  453.     IfTrace1((MustTraceCalls), "Destroy(%z)\n", obj);
  454.  
  455.     if (obj == NULL)
  456.         return (NULL);
  457.     if (ISIMMORTAL(obj->flag))
  458.     {
  459.         IfTrace1(TRUE, "Destroy of immortal object %z ignored\n", obj);
  460.         return (NULL);
  461.     }
  462.     if (ISPATHTYPE(obj->type))
  463.         KillPath(obj);
  464.     else
  465.     {
  466.         switch (obj->type)
  467.         {
  468.         case REGIONTYPE:
  469.             KillRegion(obj);
  470.             break;
  471.         case SPACETYPE:
  472.             KillSpace(obj);
  473.             break;
  474.         case LINESTYLETYPE:
  475.             KillLineStyle(obj);
  476.             break;
  477.         case FONTTYPE:
  478.             KillFont(obj);
  479.             break;
  480.         case PICTURETYPE:
  481.             KillPicture(obj);
  482.             break;
  483.         case STROKEPATHTYPE:
  484.             KillStrokePath(obj);
  485.             break;
  486.         case CLUTTYPE:
  487.             KillCLUT(obj);
  488.             break;
  489.         default:
  490.             return (ArgErr("Destroy: invalid object", obj, NULL));
  491.         }
  492.     }
  493.     return (NULL);
  494. }
  495.  
  496.  
  497. /*
  498.  * An object is unique (and directly alterable) if there is only one
  499.  * reference to it, and it is not permanent (in which case we increment
  500.  * the reference count, so we don't have to check the permanent bit).
  501.  * 3-26-91 PNM
  502.  *
  503.  * Note the rules for making a unique object:
  504.  * &drawing.
  505.  *    IF  (obj->references = 1)    return(obj);
  506.  *    ELSE (references > 1)
  507.  *        IF (ISPERMANENT(obj->flag))    return(Dupxxx(obj));
  508.  *        ELSE (nonunique, temporary object!)
  509.  *            obj->references--; return(Dupxxx(obj));
  510.  * &edrawing.
  511.  * If we must make a Copy of a nonunique, temporary object, we decrement
  512.  * reference count of the original object!
  513.  */
  514.  
  515.  
  516. /*
  517.  * Unique() - Make a Unique Object
  518.  *
  519.  * Here is a generic 'Unique' function if the object type is not known.
  520.  * Why didn't we build it with the MAKEUNIQUE macro, you ask?  Well, we
  521.  * used to, but there is at least one damn compiler in the world that
  522.  * raises errors if the types of an "(a) ? b : c" expression do not match.
  523.  * Also, when we changed Dup() to retain the permanent/temporary flag, we
  524.  * wanted to make sure "Unique" always returned a temporary object.
  525.  *
  526.  * Note that we cannot use Dup() to create a copy of the object in question,
  527.  * because Dup() may simply bump the reference count, and not return a
  528.  * unique copy to us. That is why we use t1_Copy().
  529.  *
  530.  * The purpose of this function is to make sure we have a copy of an object
  531.  * that we can safely alter:
  532.  *
  533.  * If we have a unique, temporary object, we simply return the argument.
  534.  * If we have a nonunique, temporary object, we have to make a new copy
  535.  *   of it, and decrement the reference count of the original object, to reflect
  536.  *   the fact that we traded temporary handles.
  537.  * If we have a permanent object, we make a temporary copy of it, but
  538.  *   we do not decrement the reference count of the original permanent object,
  539.  *   because permanent objects, by definition, are persistent. 3-2-6-91 PNM
  540.  */
  541. struct xobject *t1_Unique(struct xobject *obj)
  542. {
  543.     /* if the original object is not already unique, make a unique
  544.        copy...Note also that if the object was not permanent, we must
  545.        consume the old handle! 3-26-91 PNM
  546.        NOTE : consumption of the old handle moved to Allocate. 4-18-91 */
  547.     if (!obj || obj->references == 1)
  548.         return (obj);
  549.  
  550.     obj = Copy(obj);
  551.     /* and make sure we return a temporary object ! */
  552.     if (ISPERMANENT(obj->flag))
  553.     {
  554.         obj->flag &= ~ISPERMANENT(ON);
  555.         obj->references--;
  556.     }
  557.     return (obj);
  558. }
  559.  
  560.  
  561. /*
  562.  * Initialization, Error, and Debug Routines
  563.  *
  564.  * Declarations for Debug Purposes
  565.  *
  566.  * We declare all the debug flags here.
  567.  */
  568.  
  569. char *ErrorMessage = NULL;
  570.  
  571.  
  572. #ifdef AMISHDEBUG
  573. /*
  574.  * Pragmatics() - Set/Reset Debug Flags
  575.  *
  576.  * We provide a controlled way for the TYPE1IMAGER user to set and reset
  577.  * our debugging and tracing:
  578.  */
  579. void Pragmatics(
  580.         char *username,        /* name of the flag */
  581.         int value)        /* value to set it to */
  582. {
  583.     char *p;            /* temporary loop variable                      */
  584. #define    NAMESIZE   40
  585.     char name[NAMESIZE];        /* buffer to store my copy of 'username'        */
  586.  
  587.     if (strlen(username) >= (unsigned) NAMESIZE)
  588.         t1_abort("Pragmatics name too large");
  589.     strcpy(name, username);
  590.     for (p = name; *p != '\0'; p++)
  591.         *p = toupper(*p);
  592.  
  593.     if (!strcmp(name, "ALL"))
  594.         MustTraceCalls = InternalTrace =    /* MustCrash = */
  595.             LineIOTrace = value;
  596.  
  597.     else if (!strcmp(name, "LINEIOTRACE"))
  598.         LineIOTrace = value;
  599.  
  600.     else if (!strcmp(name, "TRACECALLS"))
  601.         MustTraceCalls = value;
  602.  
  603.     else if (!strcmp(name, "CHECKARGS"))
  604.         MustCheckArgs = value;
  605.  
  606.     else if (!strcmp(name, "PROCESSHINTS"))
  607.         ProcessHints = value;
  608.  
  609.     else if (!strcmp(name, "SAVEFONTPATHS"))
  610.         SaveFontPaths = value;
  611.  
  612.     else if (!strcmp(name, "CRASTERCOMPRESSIONTYPE"))
  613.         CRASTERCompressionType = value;
  614.  
  615.     else if (!strcmp(name, "CRASHONUSERERROR"))
  616.         MustCrash = value;
  617.  
  618.     else if (!strcmp(name, "DEBUG"))
  619.         StrokeDebug = SpaceDebug = PathDebug = ConicDebug = LineDebug =
  620.             RegionDebug = MemoryDebug = FontDebug =
  621.             HintDebug = ImageDebug = OffPageDebug = value;
  622.  
  623.     else if (!strcmp(name, "CONICDEBUG"))
  624.         ConicDebug = value;
  625.  
  626.     else if (!strcmp(name, "LINEDEBUG"))
  627.         LineDebug = value;
  628.  
  629.     else if (!strcmp(name, "REGIONDEBUG"))
  630.         RegionDebug = value;
  631.  
  632.     else if (!strcmp(name, "PATHDEBUG"))
  633.         PathDebug = value;
  634.  
  635.     else if (!strcmp(name, "SPACEDEBUG"))
  636.         SpaceDebug = value;
  637.  
  638.     else if (!strcmp(name, "STROKEDEBUG"))
  639.         StrokeDebug = value;
  640.  
  641.     else if (!strcmp(name, "MEMORYDEBUG"))
  642.         MemoryDebug = value;
  643.  
  644.     else if (!strcmp(name, "FONTDEBUG"))
  645.         FontDebug = value;
  646.  
  647.     else if (!strcmp(name, "HINTDEBUG"))
  648.         HintDebug = value;
  649.  
  650.     else if (!strcmp(name, "IMAGEDEBUG"))
  651.         ImageDebug = value;
  652.  
  653.     else if (!strcmp(name, "OFFPAGEDEBUG"))
  654.         OffPageDebug = value;
  655.  
  656. //#ifdef  MC68000
  657. ///*
  658. //The following pragmatics flag turns on or off instruction histograming
  659. //for performance analysis.  It is only defined in the Delta card
  660. //environment.
  661. //*/
  662. //    else if (!strcmp(name, "PROFILE"))
  663. //    {
  664. //        if (value)
  665. //            StartProfile();
  666. //        else
  667. //            StopProfile();
  668. //    }
  669. //#endif
  670.     else if (!strcmp(name, "FLUSHCACHE"))
  671.     {
  672. #ifdef notdef
  673.         while (GimeSpace())
  674.         {;
  675.         }
  676. #endif
  677.     }
  678.  
  679.     else if (!strcmp(name, "CACHEDCHARS"))
  680.         CachedChars = (value <= 0) ? 1 : value;
  681.  
  682.     else if (!strcmp(name, "CACHEDFONTS"))
  683.         CachedFonts = (value <= 0) ? 1 : value;
  684.  
  685.     else if (!strcmp(name, "CACHEBLIMIT"))
  686.         CacheBLimit = value;
  687.  
  688.     else if (!strcmp(name, "CONTINUITY"))
  689.         Continuity = value;
  690.  
  691.  
  692.     else
  693.     {
  694. //        printf("Pragmatics flag = '%s'\n", name);
  695.         ArgErr("Pragmatics:  flag not known", NULL, NULL);
  696.     }
  697.     return;
  698. }
  699. #endif
  700.  
  701.  
  702. /*
  703.  * Consume() - Consume a List of Arguments
  704.  *
  705.  * This general purpose routine is provided in the case where the object
  706.  * type(s) to be consumed are unknown or not yet verified, and/or it is
  707.  * not known whether the object is permanent.
  708.  *
  709.  * If the type of the argument is known, it is faster to directly consume
  710.  * that type, for example, ConsumeRegion() or ConsumePath().  Furthermore,
  711.  * if it is already known that the object is temporary, it is faster to
  712.  * just kill it rather than consume it, for example, KillSpace().
  713.  */
  714. void Consume(int n, struct xobject *obj1, struct xobject *obj2, struct xobject *obj3)
  715. {
  716.     switch (n)
  717.     {
  718.  
  719.     case 0:
  720.         return;
  721.  
  722.     case 1:
  723.         if (obj1 != NULL && !ISPERMANENT(obj1->flag))
  724.             Destroy(obj1);
  725.         return;
  726.  
  727.     case 2:
  728.         if (obj1 != NULL && !ISPERMANENT(obj1->flag))
  729.             Destroy(obj1);
  730.         if (obj2 != NULL && !ISPERMANENT(obj2->flag))
  731.             Destroy(obj2);
  732.         return;
  733.  
  734.     case 3:
  735.         if (obj1 != NULL && !ISPERMANENT(obj1->flag))
  736.             Destroy(obj1);
  737.         if (obj2 != NULL && !ISPERMANENT(obj2->flag))
  738.             Destroy(obj2);
  739.         if (obj3 != NULL && !ISPERMANENT(obj3->flag))
  740.             Destroy(obj3);
  741.         return;
  742.  
  743.     default:
  744.         t1_abort("Consume:  too many objects");
  745.     }
  746. }
  747.  
  748.  
  749. /*
  750.  * TypeErr() - Handles "Invalid Object Type" Errors
  751.  */
  752. struct xobject *t1_TypeErr(
  753.         char *name,            /* Name of routine (for error message)          */
  754.         struct xobject *obj,        /* Object in error                              */
  755.         int expect,            /* type expected                                */
  756.         struct xobject *ret)        /* object to return to caller                   */
  757. {
  758.     static char typemsg[80];
  759.  
  760.     if (MustCrash)
  761.         LineIOTrace = TRUE;
  762.  
  763. //    sprintf(typemsg, "Wrong object type in %s; expected %s.\n",
  764. //        name, TypeFmt(expect), TypeFmt(obj->type));
  765. //    sprintf(typemsg, "Wrong object type in %s\n", name);
  766.     strcpy(typemsg, "Wrong object type in ");
  767.     strcat(typemsg, name);
  768.     strcat(typemsg, "\n");
  769. //    IfTrace0(TRUE, typemsg);
  770.  
  771. //    ObjectPostMortem(obj);
  772.  
  773.     if (MustCrash)
  774.         t1_abort("Terminating because of CrashOnUserError...");
  775.     else
  776.         ErrorMessage = typemsg;
  777.  
  778. /* changed ISPERMANENT to ret->references > 1 3-26-91 PNM */
  779.     if (ret != NULL && (ret->references > 1))
  780.         ret = Dup(ret);
  781.     return (ret);
  782. }
  783.  
  784.  
  785. #ifdef AMISHDEBUG
  786. /*
  787.  * TypeFmt() - Returns Pointer to English Name of Object Type
  788.  *
  789.  * This is a subroutine of TypeErr().
  790.  */
  791. static char *TypeFmt(int type)
  792. {
  793.     char *r;
  794.  
  795.     if (ISPATHTYPE(type))
  796.         if (type == TEXTTYPE)
  797.             r = "path or region (from TextPath)";
  798.         else
  799.             r = "path";
  800.     else
  801.     {
  802.         switch (type)
  803.         {
  804.         case INVALIDTYPE:
  805.             r = "INVALID (previously consumed?)";
  806.             break;
  807.         case REGIONTYPE:
  808.             r = "region";
  809.             break;
  810.         case SPACETYPE:
  811.             r = "XYspace";
  812.             break;
  813.         case LINESTYLETYPE:
  814.             r = "linestyle";
  815.             break;
  816.         case FONTTYPE:
  817.             r = "font";
  818.             break;
  819.         case PICTURETYPE:
  820.             r = "picture";
  821.             break;
  822.         case STROKEPATHTYPE:
  823.             r = "path (from StrokePath)";
  824.             break;
  825.         default:
  826.             r = "UNKNOWN";
  827.             break;
  828.         }
  829.     }
  830.     return (r);
  831. }
  832. #endif /* AMISHDEBUG */
  833.  
  834.  
  835. #ifdef AMISHDEBUG
  836. /*
  837.  * ObjectPostMortem() - Prints as Much as We Can About a Bad Object
  838.  *
  839.  * This is a subroutine of TypeErr() and ArgErr().
  840.  */
  841. static void ObjectPostMortem(struct xobject *obj)
  842. {
  843.     extern struct XYspace *USER;
  844.  
  845.     Pragmatics("Debug", 10);
  846.     IfTrace2(TRUE, "Bad object is of %s type %z\n", TypeFmt(obj->type), obj);
  847.  
  848.     IfTrace0((obj == (struct xobject *)USER),
  849.          "Suspect that InitImager() was omitted.\n");
  850.     Pragmatics("Debug", 0);
  851. }
  852. #endif /* AMISHDEBUG */
  853.  
  854.  
  855. /*
  856.  * ArgErr() - Invalid Argument Passed to a Routine
  857.  *
  858.  * A common routine to report argument errors.  It is usually called
  859.  * is returned to the caller in case MustCrash is FALSE and ArgErr
  860.  * returns to its caller.
  861.  */
  862.  
  863. struct xobject *t1_ArgErr(
  864.      char *string,            /* description of error */
  865.      struct xobject *obj,        /* object, if any, that was in error */
  866.      struct xobject *ret)        /* object returned to caller or NULL */
  867. {
  868.     if (MustCrash)
  869.         LineIOTrace = TRUE;
  870.     IfTrace1(TRUE, "ARGUMENT ERROR-- %s.\n", string);
  871. //    if (obj != NULL)
  872. //        ObjectPostMortem(obj);
  873.     if (MustCrash)
  874.         t1_abort("Terminating because of CrashOnUserError...");
  875.     else
  876.         ErrorMessage = string;
  877.     return (ret);
  878. }
  879.  
  880.  
  881. /*
  882.  * t1_abort() - Crash Due to Error
  883.  *
  884.  * Defined in objects.h to be FatalError(), the server's abort routine.
  885.  */
  886.  
  887.  
  888. /*
  889.  * REAL Miscellaneous Stuff
  890.  * ErrorMsg() - Return the User an Error Message
  891.  */
  892. char *ErrorMsg(void)
  893. {
  894.     char *r;
  895.  
  896.     r = ErrorMessage;
  897.     ErrorMessage = NULL;
  898.     return (r);
  899. }
  900.  
  901.